package com.starlink.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageHelper;
import com.starlink.common.enums.ErrorCode;
import com.starlink.common.exception.BusinessException;
import com.starlink.common.utils.AssertUtil;
import com.starlink.context.SessionContext;
import com.starlink.mapper.PointsAcquireBillMapper;
import com.starlink.model.domain.PointsAcquireBillDO;
import com.starlink.model.dtomapper.PointsAcquireBillDtoMapper;
import com.starlink.model.request.PointsAcquireBillRequest;
import com.starlink.model.vo.PointsAcquireBillVO;
import com.starlink.model.vo.PointsVO;
import com.starlink.service.PointsAcquireBillService;
import com.starlink.service.PointsService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.domain.Pageable;
import com.starlink.model.dtomapper.PointsUseBillDtoMapper;
import com.starlink.model.domain.PointsUseBillDO;
import com.starlink.mapper.PointsUseBillMapper;
import com.starlink.model.request.PointsUseBillRequest;
import com.starlink.model.vo.PointsUseBillVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.starlink.common.enums.AcquireModeEnum.*;
import static com.starlink.utils.IDUtils.getId;
import static com.starlink.utils.PageUtils.getOrderBy;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

/**
 * @author zhanghong
 */
@Service
public class PointsServiceImpl extends ServiceImpl<PointsUseBillMapper, PointsUseBillDO> implements PointsService {
    @Autowired
    private PointsUseBillMapper useBillMapper; //使用
    @Autowired
    private PointsAcquireBillMapper acquireBillMapper; //获取
    @Autowired
    private PointsAcquireBillService acquireBillService;

    @Override
    public PageInfo<PointsAcquireBillVO> pageQueryPointsAcquireBill(Pageable pageable, PointsAcquireBillRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        List<PointsAcquireBillVO> list = acquireBillMapper.pageQueryPointsUseBill(request);
        return new PageInfo(list);
    }

    @Override
    public PageInfo<PointsUseBillVO> pageQueryPointsUseBill(Pageable pageable, PointsUseBillRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        List<PointsUseBillVO> list = useBillMapper.pageQueryPointsUseBill(request);
        return new PageInfo(list);
    }

    @Override
    public PointsVO selectPointInfo(Long userId) {
        PointsVO vo = new PointsVO();
        List<PointsUseBillDO> useBillDOS = this.lambdaQuery().eq(PointsUseBillDO::getUserId, userId)
                .last("FOR UPDATE")
                .list();
        List<PointsAcquireBillDO> acquireBillDOS = acquireBillService.lambdaQuery().eq(PointsAcquireBillDO::getUserId, userId)
                .last("FOR UPDATE")
                .list();
        if (CollectionUtils.isNotEmpty(useBillDOS)) {
            int consum = useBillDOS.stream().mapToInt(PointsUseBillDO::getConsumePonts).sum();//消费积分
            vo.setUsedPoints(Long.valueOf(consum));
        } else {
            vo.setUsedPoints(0L);
        }
        if (CollectionUtils.isNotEmpty(acquireBillDOS)) {
            int sum = acquireBillDOS.stream().mapToInt(PointsAcquireBillDO::getAcquirePoint).sum();//获取的积分
            vo.setTotalPoints(Long.valueOf(sum));
        } else {
            vo.setTotalPoints(0L);
        }
        vo.setAvailablePoints(vo.getTotalPoints() - vo.getUsedPoints());
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addPoint(PointsAcquireBillRequest request) {
        Long userId = request.getUserId();
        if (userId == null) {
            userId = SessionContext.getWechatUserId();
            request.setUserId(userId);
        }
        Integer acquireMode = request.getAcquireMode();
        Integer title = request.getTitle();
        Integer acquirePoint = request.getAcquirePoint();
        AssertUtil.assertNotNull(acquireMode, "获取方式不能为空!");
        AssertUtil.assertNotNull(title, "行为动作不能为空!");
        AssertUtil.assertNotNull(acquirePoint, "积分不能为空!");
        // 获取当前日期的格式化字符串，不包含时分秒
        String currentDateString = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        if (XIN_SHOU.getType().equals(acquireMode)) {
            PointsAcquireBillDO acquireBillDO = acquireBillService.lambdaQuery()
                    .eq(PointsAcquireBillDO::getAcquireMode, acquireMode)
                    .eq(PointsAcquireBillDO::getTitle, title)
                    .eq(PointsAcquireBillDO::getUserId, userId)
                    .one();
            AssertUtil.assertNull(acquireBillDO, "该行为积分不可重复获取!");
        }
        if (CHUAN_BO.getType().equals(acquireMode)) {
            List<PointsAcquireBillDO> acquireBillDOs = acquireBillService.lambdaQuery()
                    .eq(PointsAcquireBillDO::getAcquireMode, acquireMode)
                    .eq(PointsAcquireBillDO::getUserId, userId)
                    .apply("DATE_FORMAT(create_time, '%Y-%m-%d') = '" + currentDateString + "'")
                    .list();
            if (CollectionUtils.isNotEmpty(acquireBillDOs)) {
                if (acquireBillDOs.size() >= 2) {
                    throw new BusinessException(ErrorCode.ADD_POINT_MAX_ERROR);
                }
            }
        }
        if (RI_CHANG.getType().equals(acquireMode)) {
            PointsAcquireBillDO acquireBillDO = acquireBillService.lambdaQuery()
                    .eq(PointsAcquireBillDO::getAcquireMode, acquireMode)
                    .eq(PointsAcquireBillDO::getTitle, title)
                    .eq(PointsAcquireBillDO::getUserId, userId)
                    .apply("DATE_FORMAT(create_time, '%Y-%m-%d') = '" + currentDateString + "'")
                    .one();
            AssertUtil.assertNull(acquireBillDO, ErrorCode.ADD_POINT_MAX_ERROR);
        }
        request.setCreateTime(new Date());
        request.setId(getId());
        acquireBillMapper.insertDO(PointsAcquireBillDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void consumPoint(PointsUseBillRequest request) {
        Integer consumePonts = request.getConsumePonts();
        Integer title = request.getTitle();
        Integer consumeMode = request.getConsumeMode();
        AssertUtil.assertNotNull(consumeMode, "消费方式不能为空!");
        AssertUtil.assertNotNull(title, "行为动作不能为空!");
        AssertUtil.assertNotNull(consumePonts, "积分不能为空!");
        useBillMapper.insertDO(PointsUseBillDtoMapper.INSTANCE.request2DO(request));
    }

}
